package blog.wls.jmx.appmbean.client;

import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.MBeanServerNotification;
import javax.management.AttributeChangeNotification;

import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;

import java.util.Date;

/**
 * This class implements a JMX listener that output the event it receives
 * to a stream
 *
 * @author Philippe.Le.Mouel@Oracle.com
 */
public class NotificationListenerWriter implements NotificationListener {

    /**
     * Formating flags
     */
    private boolean displayTimeStamp_ = false;

    /**
     * Identify the listener instance
     */
    private String name_ = null;

    /**
     * Keep track of the number of events handled
     */
    private int eventCount_ = 0;

    /**
     * Used as optimization
     */
    private Date dateOpti_ = new Date();

    /**
     * The sink of events
     */
    private PrintWriter pw_ = null;


    /**
     * Construct an instance using an OutputStream as sink of events
     */
    public NotificationListenerWriter(OutputStream out) {
        pw_ = new PrintWriter(out, true);
    }


    /**
     * Construct an instance using a Writer as sink of events
     */
    public NotificationListenerWriter(Writer out) {
        pw_ = new PrintWriter(out, true);
    }


    /**
     * Construct an instance using a PrintWriter as sink of events
     */
    public NotificationListenerWriter(PrintWriter out) {
        pw_ = out;
    }


    /**
     * Construct an instance using an OutputStream as sink of events
     */
    public NotificationListenerWriter(OutputStream out, String name) {
        pw_ = new PrintWriter(out, true);
        name_ = name;
    }


    /**
     * Construct an instance using a Writer as sink of events
     */
    public NotificationListenerWriter(Writer out, String name) {
        pw_ = new PrintWriter(out, true);
        name_ = name;
    }


    /**
     * Construct an instance using a PrintWriter as sink of events
     */
    public NotificationListenerWriter(PrintWriter out, String name) {
        pw_ = out;
        name_ = name;
    }


    /**
     * Display the event's time stamp
     */
    public void setDisplayTimeStamp() {
        displayTimeStamp_ = true;
    }


    /**
     * Invoked when a JMX notification occurs. It output the received event to
     * the stream.
     *
     * @param notification - The notification.
     * @param handback     - This parameter is ignored
     */
    public void handleNotification(Notification notification, Object handback) {
        StringBuffer msg = new StringBuffer();

        if (name_ != null) {
            msg.append("Listener " + name_ + " notification " + eventCount_++ + " -->");
        }

        if (displayTimeStamp_) {
            dateOpti_.setTime(notification.getTimeStamp());
            msg.append(dateOpti_.toString());
            msg.append("::");
        }

        if (notification.getSource() != null) {
            msg.append(" source: ");
            msg.append(notification.getSource().toString());
        }

        if (notification.getType() != null) {
            msg.append(" type: ");
            msg.append(notification.getType());
        }

        if (notification.getMessage() != null) {
            msg.append(" message: ");
            msg.append(notification.getMessage());
        }

        if (notification.getUserData() != null) {
            msg.append(" user data: ");
            msg.append(notification.getUserData().toString());
        }

        if (notification instanceof MBeanServerNotification) {
            msg.append(" target MBean: ");
            msg.append(((MBeanServerNotification) notification).getMBeanName().toString());
        }

        if (notification instanceof AttributeChangeNotification) {
            AttributeChangeNotification acn= AttributeChangeNotification.class.cast(notification);
            msg.append(" attribute name: ");
            msg.append(acn.getAttributeName());
            msg.append(" attribute type: ");
            msg.append(acn.getAttributeType());
            msg.append(" old value: ");
            msg.append(acn.getOldValue());
            msg.append(" new value: ");
            msg.append(acn.getNewValue());
        }

        pw_.println(msg.toString());
    }

}
